/***************************************************************************
 *   Copyright (C) 2004-2006 by David Saxton                               *
 *   david@bluehaze.org                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#ifndef MULTIINPUTGATE_H
#define MULTIINPUTGATE_H

#include "component.h"
#include "logic.h"

const int maxGateInput = 256;

/**
@author David Saxton
*/
class MultiInputGate : public CallbackClass, public Component
{
public:
    /**
     * @param rectangularShapeText is the text displayed in the logic symbol
     * when drawing in rectangular mode, e.g. "&" for AND and "=1" for XOR.
     * @param invertedOutput true for NAND, NOR, XNOR; false for AND, OR, XOR
     * @param baseWidth is the width of the logic gate when drawing in
     * distinctive mode.
     * @param likeOR true for OR, NOR, XOR, XNOR (specifically, this value
     * used in computer the length of input pins, as OR types have a curvy
     * base when the shape is distinctive).
     */
    MultiInputGate(ICNDocument *icnDocument, bool newItem, const char *id, const QString &rectangularShapeText, bool invertedOutput, int baseWidth, bool likeOR);
    ~MultiInputGate() override;

protected:
    enum LogicSymbolShape { Distinctive, Rectangular };

    void updateAttachedPositioning() override;
    void slotUpdateConfiguration() override;
    virtual void inStateChanged(bool newState) = 0;
    /**
     * This will draw the shape if the logic symbol is currently
     * rectangular. Distinctive shapes should be drawn in the respective
     * subclasses.
     */
    void drawShape(QPainter &p) override;
    void dataChanged() override;
    void updateInputs(int newNum);
    /**
     * @return what the width should be according to the current logic
     * symbol shape.
     */
    int logicSymbolShapeToWidth() const;
    /**
     * Updates the display text for the logic symbol depending on its shape.
     */
    void updateSymbolText();

    int m_numInputs;
    int m_distinctiveWidth;
    LogicIn *inLogic[maxGateInput];
    ECNode *inNode[maxGateInput];
    LogicOut *m_pOut;
    LogicSymbolShape m_logicSymbolShape;
    QString m_rectangularShapeText;
    bool m_bInvertedOutput;
    bool m_bLikeOR;

private:
    /**
     * Reads the logic symbol shape from KTLConfig.
     */
    void updateLogicSymbolShape();

    bool m_bDoneInit;
};

/**
@short Boolean XNOR
@author David Saxton
*/
class ECXnor : public MultiInputGate
{
public:
    ECXnor(ICNDocument *icnDocument, bool newItem, const char *id = nullptr);
    ~ECXnor() override;

    static Item *construct(ItemDocument *itemDocument, bool newItem, const char *id);
    static LibraryItem *libraryItem();

protected:
    void inStateChanged(bool newState) override;
    void drawShape(QPainter &p) override;
};

/**
@short Boolean XOR
@author David Saxton
*/
class ECXor : public MultiInputGate
{
public:
    ECXor(ICNDocument *icnDocument, bool newItem, const char *id = nullptr);
    ~ECXor() override;

    static Item *construct(ItemDocument *itemDocument, bool newItem, const char *id);
    static LibraryItem *libraryItem();

protected:
    void inStateChanged(bool newState) override;
    void drawShape(QPainter &p) override;
};

/**
@short Boolean OR
@author David Saxton
*/
class ECOr : public MultiInputGate
{
public:
    ECOr(ICNDocument *icnDocument, bool newItem, const char *id = nullptr);
    ~ECOr() override;

    static Item *construct(ItemDocument *itemDocument, bool newItem, const char *id);
    static LibraryItem *libraryItem();

protected:
    void inStateChanged(bool newState) override;
    void drawShape(QPainter &p) override;
};

/**
@short Boolean NOR
@author David Saxton
*/
class ECNor : public MultiInputGate
{
public:
    ECNor(ICNDocument *icnDocument, bool newItem, const char *id = nullptr);
    ~ECNor() override;

    static Item *construct(ItemDocument *itemDocument, bool newItem, const char *id);
    static LibraryItem *libraryItem();

protected:
    void inStateChanged(bool newState) override;
    void drawShape(QPainter &p) override;
};

/**
@short Boolean NAND
@author David Saxton
*/
class ECNand : public MultiInputGate
{
public:
    ECNand(ICNDocument *icnDocument, bool newItem, const char *id = nullptr);
    ~ECNand() override;

    static Item *construct(ItemDocument *itemDocument, bool newItem, const char *id);
    static LibraryItem *libraryItem();

protected:
    void inStateChanged(bool newState) override;
    void drawShape(QPainter &p) override;
};

/**
@short Boolean AND
@author David Saxton
*/
class ECAnd : public MultiInputGate
{
public:
    ECAnd(ICNDocument *icnDocument, bool newItem, const char *id = nullptr);
    ~ECAnd() override;

    static Item *construct(ItemDocument *itemDocument, bool newItem, const char *id);
    static LibraryItem *libraryItem();

protected:
    void inStateChanged(bool newState) override;
    void drawShape(QPainter &p) override;
};

#endif
